/**
 * @file lv_hms.c
 *
 */

/*----------------------------------------------------------------------------------------------------------------------------------
/    Added normal JPG support [7/10/2020]
/    ----------
/    HMS is a custom created modified JPEG file format for small embedded platforms.
/    It will contain multiple JPEG fragments all embedded into a single file with a custom header.
/    This makes JPEG decoding easier using any JPEG library. Overall file size will be almost
/    similar to the parent jpeg file. We can generate hms from any jpeg using a python script
/    provided along with this project.
/                                                                                     (by vinodstanur | 2020 )
/    HMS FILE STRUCTURE
/    --------------------------------------------------------------------------------------------------------------------------------
/    Bytes                       |   Value                                                                                           |
/    --------------------------------------------------------------------------------------------------------------------------------
/
/    0 - 3                       |   "HMS_"
/
/    4 - 7                       |   "V000"                          [VERSION OF HMS FILE for future compatibiliby]
/
/    8 - 9                       |   X_RESOLUTION (width)            [little endian]
/
/    10 - 11                     |   Y_RESOLUTION (height)           [little endian]
/
/    12 - 13                     |   JPEG BLOCK WIDTH (16 normally)  [little endian]
/
/    14 - 15                     |   TOTAL_FRAMES inside             [little endian]
/
/    16 - [(TOTAL_FRAMES*2 )]    |   SIZE OF EACH SPLIT FRAGMENTS   (FRAME_INFO_ARRAY)
/
/   encode data                  |   Each JPEG frame can be extracted from HMS data by parsing the FRAME_INFO_ARRAY one time.
/
/----------------------------------------------------------------------------------------------------------------------------------
/                   HMS DECODER
/                   ------------
/   just replace those files with updated files.
/---------------------------------------------------------------------------------------------------------------------------------*/

/*********************
 *      INCLUDES
 *********************/

#include "../../../lvgl.h"
#if LV_USE_HMS

#include "lv_hms.h"
#include "../../../misc/lv_fs.h"

/*********************
 *      DEFINES
 *********************/
#define TJPGD_WORKBUFF_SIZE           4    //Recommended by TJPGD libray

//NEVER EDIT THESE OFFSET VALUES
#define HMS_VERSION_OFFSET            4
#define HMS_X_RES_OFFSET              8
#define HMS_Y_RES_OFFSET              10
#define HMS_BLOCK_WIDTH_OFFSET        12
#define HMS_TOTAL_FRAMES_OFFSET       14
#define HMS_FRAME_INFO_ARRAY_OFFSET   16

/**********************
 *      TYPEDEFS
 **********************/

enum io_source_type {
    HMS_IO_SOURCE_C_ARRAY,
    HMS_IO_SOURCE_DISK,
};

typedef struct {
    uint16_t left;		/* Left end */
    uint16_t right;		/* Right end */
    uint16_t top;		/* Top end */
    uint16_t bottom;	/* Bottom end */
} JRECT;

typedef struct {
    enum io_source_type type;
    lv_fs_file_t lv_file;
    uint8_t * img_cache_buff;
    int img_cache_x_res;
    int img_cache_y_res;
    uint8_t* raw_hms_data;              //Used when type==HMS_IO_SOURCE_C_ARRAY.
    uint32_t raw_hms_data_size;          //Num bytes pointed to by raw_hms_data.
    uint32_t raw_hms_data_next_read_pos; //Used for all types.
} io_source_t;

typedef struct {
    uint16_t left;
    uint16_t right;
    uint16_t color;
}HfCode_t;

typedef struct {
    uint8_t * hms_data;
    uint32_t hms_data_size;
    int hms_x_res;
    int hms_y_res;
    int hms_total_frames;
    int hms_frame_height;
    int hms_cache_frame_index;
    uint16_t* frame_size;
    uint8_t** frame_base_array;        //to save base address of each split frames upto hms_total_frames.
    int*      frame_base_offset;       //to save base offset for fseek
    uint8_t*  frame_cache;
    uint32_t* workb;                    //JPG work buffer for jpeg library
    uint16_t  worksize;
    io_source_t io;

    uint8_t  enc_byte;
    uint32_t enc_word;
    uint32_t enc_bits;

} HMS;

/**********************
 *  STATIC PROTOTYPES
 **********************/
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
                                  lv_coord_t len, uint8_t * buf);
static lv_res_t hms_prepare(HMS* hms);
static lv_res_t hms_decode(HMS* hms);
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
static size_t input_func(HMS *hms, uint8_t * buff, size_t ndata);
static void lv_hms_cleanup(HMS * hms);
static void lv_hms_free(HMS * hms);

/**********************
 *  STATIC VARIABLES
 **********************/
static HfCode_t huffTree[] = {
    {     1,   896, 0xffff },
    {     3,     2, 0xffff },
    {     5,     4, 0xffff },
    {     7,     6, 0xffff },
    {     9,     8, 0xffff },
    {   895,    10, 0xffff },
    {   894,    11, 0xffff },
    {    13,    12, 0xffff },
    {    15,    14, 0xffff },
    {    17,    16, 0xffff },
    {    19,    18, 0xffff },
    {   892,   893, 0xffff },
    {   891,    20, 0xffff },
    {   890,    21, 0xffff },
    {   888,   889, 0xffff },
    {   887,    22, 0xffff },
    {    24,    23, 0xffff },
    {    26,    25, 0xffff },
    {    28,    27, 0xffff },
    {    30,    29, 0xffff },
    {    31,   886, 0xffff },
    {    33,    32, 0xffff },
    {    35,    34, 0xffff },
    {    37,    36, 0xffff },
    {   885,    38, 0xffff },
    {    40,    39, 0xffff },
    {    42,    41, 0xffff },
    {   883,   884, 0xffff },
    {    44,    43, 0xffff },
    {    46,    45, 0xffff },
    {    48,    47, 0xffff },
    {    49,   882, 0xffff },
    {    50,   881, 0xffff },
    {    52,    51, 0xffff },
    {   880,    53, 0xffff },
    {    55,    54, 0xffff },
    {   879,    56, 0xffff },
    {   878,    57, 0xffff },
    {    59,    58, 0xffff },
    {   877,    60, 0xffff },
    {    62,    61, 0xffff },
    {   876,    63, 0xffff },
    {    64,   875, 0xffff },
    {    66,    65, 0xffff },
    {    67,   874, 0xffff },
    {    69,    68, 0xffff },
    {    70,   873, 0xffff },
    {   872,    71, 0xffff },
    {    73,    72, 0xffff },
    {    74,   871, 0xffff },
    {   869,   870, 0xffff },
    {    75,   868, 0xffff },
    {    77,    76, 0xffff },
    {    79,    78, 0xffff },
    {   867,    80, 0xffff },
    {   866,    81, 0xffff },
    {    83,    82, 0xffff },
    {   865,    84, 0xffff },
    {   864,    85, 0xffff },
    {    86,   863, 0xffff },
    {   862,    87, 0xffff },
    {    88,   861, 0xffff },
    {   859,   860, 0xffff },
    {    90,    89, 0xffff },
    {   858,    91, 0xffff },
    {   856,   857, 0xffff },
    {   855,    92, 0xffff },
    {    93,   854, 0xffff },
    {   852,   853, 0xffff },
    {   850,   851, 0xffff },
    {   849,    94, 0xffff },
    {    95,   848, 0xffff },
    {   847,    96, 0xffff },
    {   846,    97, 0xffff },
    {   845,    98, 0xffff },
    {   100,    99, 0xffff },
    {   844,   101, 0xffff },
    {   842,   843, 0xffff },
    {   841,   102, 0xffff },
    {   840,   103, 0xffff },
    {   839,   104, 0xffff },
    {   105,   838, 0xffff },
    {   837,   106, 0xffff },
    {   108,   107, 0xffff },
    {   109,   836, 0xffff },
    {   111,   110, 0xffff },
    {   835,   834, 0xffff },
    {   113,   112, 0xffff },
    {   115,   114, 0xffff },
    {   833,   116, 0xffff },
    {   832,   117, 0xffff },
    {   831,   118, 0xffff },
    {   120,   119, 0xffff },
    {   121,   830, 0xffff },
    {   829,   122, 0xffff },
    {   828,   123, 0xffff },
    {   125,   124, 0xffff },
    {   127,   126, 0xffff },
    {   827,   128, 0xffff },
    {   130,   129, 0xffff },
    {   132,   131, 0xffff },
    {   133,   826, 0xffff },
    {   135,   134, 0xffff },
    {   136,   825, 0xffff },
    {   138,   137, 0xffff },
    {   140,   139, 0xffff },
    {   823,   824, 0xffff },
    {   142,   141, 0xffff },
    {   144,   143, 0xffff },
    {   146,   145, 0xffff },
    {   822,   147, 0xffff },
    {   148,   821, 0xffff },
    {   150,   149, 0xffff },
    {   152,   151, 0xffff },
    {   153,   820, 0xffff },
    {   155,   154, 0xffff },
    {   157,   156, 0xffff },
    {   158,   819, 0xffff },
    {   160,   159, 0xffff },
    {   161,   818, 0xffff },
    {   162,   817, 0xffff },
    {   164,   163, 0xffff },
    {   165,   816, 0xffff },
    {   166,   815, 0xffff },
    {   168,   167, 0xffff },
    {   169,   814, 0xffff },
    {   171,   170, 0xffff },
    {   813,   172, 0xffff },
    {   173,   812, 0xffff },
    {   811,   174, 0xffff },
    {   810,   175, 0xffff },
    {   177,   176, 0xffff },
    {   179,   178, 0xffff },
    {   181,   180, 0xffff },
    {   182,   809, 0xffff },
    {   183,   808, 0xffff },
    {   806,   184, 0xffff },
    {   185,   807, 0xffff },
    {   805,   186, 0xffff },
    {   188,   187, 0xffff },
    {   803,   804, 0xffff },
    {   190,   189, 0xffff },
    {   802,   191, 0xffff },
    {   801,   192, 0xffff },
    {   800,   193, 0xffff },
    {   799,   194, 0xffff },
    {   798,   195, 0xffff },
    {   197,   196, 0xffff },
    {   199,   198, 0xffff },
    {   200,   797, 0xffff },
    {   201,   796, 0xffff },
    {   794,   795, 0xffff },
    {   202,   793, 0xffff },
    {   204,   203, 0xffff },
    {   205,   792, 0xffff },
    {   206,   791, 0xffff },
    {   789,   790, 0xffff },
    {   788,   207, 0xffff },
    {   208,   787, 0xffff },
    {   209,   786, 0xffff },
    {   785,   210, 0xffff },
    {   212,   211, 0xffff },
    {   784,   213, 0xffff },
    {   783,   214, 0xffff },
    {   215,   782, 0xffff },
    {   216,   781, 0xffff },
    {   780,   779, 0xffff },
    {   217,   778, 0xffff },
    {   776,   777, 0xffff },
    {   219,   218, 0xffff },
    {   773,   775, 0xffff },
    {   220,   774, 0xffff },
    {   771,   772, 0xffff },
    {   770,   221, 0xffff },
    {   223,   222, 0xffff },
    {   769,   224, 0xffff },
    {   226,   225, 0xffff },
    {   227,   768, 0xffff },
    {   766,   767, 0xffff },
    {   228,   765, 0xffff },
    {   229,   764, 0xffff },
    {   762,   763, 0xffff },
    {   230,   761, 0xffff },
    {   232,   231, 0xffff },
    {   233,   760, 0xffff },
    {   759,   234, 0xffff },
    {   758,   235, 0xffff },
    {   757,   236, 0xffff },
    {   237,   756, 0xffff },
    {   755,   238, 0xffff },
    {   753,   754, 0xffff },
    {   752,   239, 0xffff },
    {   240,   751, 0xffff },
    {   749,   750, 0xffff },
    {   747,   748, 0xffff },
    {   242,   241, 0xffff },
    {   244,   243, 0xffff },
    {   746,   245, 0xffff },
    {   744,   745, 0xffff },
    {   247,   246, 0xffff },
    {   248,   743, 0xffff },
    {   249,   742, 0xffff },
    {   250,   741, 0xffff },
    {   252,   251, 0xffff },
    {   740,   739, 0xffff },
    {   253,   738, 0xffff },
    {   736,   737, 0xffff },
    {   254,   735, 0xffff },
    {   734,   255, 0xffff },
    {   733,   256, 0xffff },
    {   257,   732, 0xffff },
    {   259,   258, 0xffff },
    {   260,   731, 0xffff },
    {   261,   730, 0xffff },
    {   263,   262, 0xffff },
    {   264,   729, 0xffff },
    {   727,   728, 0xffff },
    {   266,   265, 0xffff },
    {   726,   267, 0xffff },
    {   268,   725, 0xffff },
    {   723,   724, 0xffff },
    {   721,   722, 0xffff },
    {   270,   269, 0xffff },
    {   271,   720, 0xffff },
    {   718,   719, 0xffff },
    {   717,   272, 0xffff },
    {   715,   716, 0xffff },
    {   714,   273, 0xffff },
    {   275,   274, 0xffff },
    {   277,   276, 0xffff },
    {   712,   713, 0xffff },
    {   278,   711, 0xffff },
    {   709,   710, 0xffff },
    {   708,   279, 0xffff },
    {   707,   280, 0xffff },
    {   706,   705, 0xffff },
    {   704,   281, 0xffff },
    {   283,   282, 0xffff },
    {   284,   703, 0xffff },
    {   285,   702, 0xffff },
    {   701,   286, 0xffff },
    {   287,   700, 0xffff },
    {   699,   698, 0xffff },
    {   696,   697, 0xffff },
    {   695,   288, 0xffff },
    {   289,   694, 0xffff },
    {   692,   693, 0xffff },
    {   691,   290, 0xffff },
    {   689,   690, 0xffff },
    {   687,   291, 0xffff },
    {   292,   688, 0xffff },
    {   685,   686, 0xffff },
    {   293,   684, 0xffff },
    {   294,   683, 0xffff },
    {   296,   295, 0xffff },
    {   298,   297, 0xffff },
    {   681,   682, 0xffff },
    {   300,   299, 0xffff },
    {   679,   680, 0xffff },
    {   301,   678, 0xffff },
    {   302,   677, 0xffff },
    {   675,   303, 0xffff },
    {   304,   676, 0xffff },
    {   305,   674, 0xffff },
    {   673,   306, 0xffff },
    {   672,   307, 0xffff },
    {   671,   308, 0xffff },
    {   309,   670, 0xffff },
    {   311,   310, 0xffff },
    {   667,   669, 0xffff },
    {   312,   668, 0xffff },
    {   666,   313, 0xffff },
    {   665,   314, 0xffff },
    {   663,   664, 0xffff },
    {   662,   315, 0xffff },
    {   316,   661, 0xffff },
    {   660,   317, 0xffff },
    {   318,   659, 0xffff },
    {   319,   658, 0xffff },
    {   657,   656, 0xffff },
    {   321,   320, 0xffff },
    {   654,   655, 0xffff },
    {   323,   322, 0xffff },
    {   652,   653, 0xffff },
    {   651,   324, 0xffff },
    {   649,   650, 0xffff },
    {   326,   325, 0xffff },
    {   648,   327, 0xffff },
    {   647,   646, 0xffff },
    {   645,   328, 0xffff },
    {   644,   329, 0xffff },
    {   331,   330, 0xffff },
    {   642,   643, 0xffff },
    {   641,   332, 0xffff },
    {   334,   333, 0xffff },
    {   638,   640, 0xffff },
    {   335,   639, 0xffff },
    {   336,   637, 0xffff },
    {   337,   636, 0xffff },
    {   339,   338, 0xffff },
    {   635,   340, 0xffff },
    {   341,   634, 0xffff },
    {   631,   633, 0xffff },
    {   630,   632, 0xffff },
    {   629,   342, 0xffff },
    {   627,   628, 0xffff },
    {   344,   343, 0xffff },
    {   626,   345, 0xffff },
    {   624,   625, 0xffff },
    {   347,   346, 0xffff },
    {   622,   623, 0xffff },
    {   349,   348, 0xffff },
    {   350,   621, 0xffff },
    {   620,   619, 0xffff },
    {   618,   351, 0xffff },
    {   352,   617, 0xffff },
    {   353,   616, 0xffff },
    {   615,   354, 0xffff },
    {   356,   355, 0xffff },
    {   357,   614, 0xffff },
    {   612,   613, 0xffff },
    {   611,   358, 0xffff },
    {   610,   359, 0xffff },
    {   608,   609, 0xffff },
    {   361,   360, 0xffff },
    {   362,   607, 0xffff },
    {   363,   606, 0xffff },
    {   605,   364, 0xffff },
    {   604,   365, 0xffff },
    {   366,   603, 0xffff },
    {   367,   602, 0xffff },
    {   368,   601, 0xffff },
    {   370,   369, 0xffff },
    {   371,   600, 0xffff },
    {   597,   599, 0xffff },
    {   372,   598, 0xffff },
    {   373,   596, 0xffff },
    {   595,   594, 0xffff },
    {   592,   591, 0xffff },
    {   374,   593, 0xffff },
    {   589,   590, 0xffff },
    {   375,   588, 0xffff },
    {   376,   587, 0xffff },
    {   377,   586, 0xffff },
    {   585,   378, 0xffff },
    {   584,   583, 0xffff },
    {   380,   379, 0xffff },
    {   582,   581, 0xffff },
    {   579,   580, 0xffff },
    {   578,   381, 0xffff },
    {   577,   382, 0xffff },
    {   384,   383, 0xffff },
    {   576,   385, 0xffff },
    {   575,   386, 0xffff },
    {   574,   573, 0xffff },
    {   571,   387, 0xffff },
    {   570,   572, 0xffff },
    {   569,   388, 0xffff },
    {   389,   568, 0xffff },
    {   567,   390, 0xffff },
    {   566,   565, 0xffff },
    {   391,   564, 0xffff },
    {   563,   392, 0xffff },
    {   562,   393, 0xffff },
    {   561,   394, 0xffff },
    {   560,   395, 0xffff },
    {   397,   396, 0xffff },
    {   398,   559, 0xffff },
    {   558,   399, 0xffff },
    {   400,   557, 0xffff },
    {   556,   401, 0xffff },
    {   403,   402, 0xffff },
    {   554,   553, 0xffff },
    {   404,   555, 0xffff },
    {   552,   405, 0xffff },
    {   406,   551, 0xffff },
    {   407,   550, 0xffff },
    {   548,   547, 0xffff },
    {   408,   549, 0xffff },
    {   545,   546, 0xffff },
    {   543,   544, 0xffff },
    {   541,   542, 0xffff },
    {   540,   409, 0xffff },
    {   411,   410, 0xffff },
    {   539,   538, 0xffff },
    {   536,   412, 0xffff },
    {   413,   537, 0xffff },
    {   414,   535, 0xffff },
    {   533,   534, 0xffff },
    {   415,   532, 0xffff },
    {   530,   531, 0xffff },
    {   528,   416, 0xffff },
    {   417,   529, 0xffff },
    {   524,   527, 0xffff },
    {   526,   525, 0xffff },
    {   523,   418, 0xffff },
    {   420,   419, 0xffff },
    {   421,   522, 0xffff },
    {   423,   422, 0xffff },
    {   521,   424, 0xffff },
    {   519,   518, 0xffff },
    {   425,   520, 0xffff },
    {   517,   426, 0xffff },
    {   428,   427, 0xffff },
    {   515,   429, 0xffff },
    {   430,   516, 0xffff },
    {   514,   513, 0xffff },
    {   432,   431, 0xffff },
    {   511,   512, 0xffff },
    {   434,   433, 0xffff },
    {   507,   510, 0xffff },
    {   509,   508, 0xffff },
    {   435,   506, 0xffff },
    {   436,   505, 0xffff },
    {   437,   504, 0xffff },
    {   503,   502, 0xffff },
    {   439,   438, 0xffff },
    {   499,   501, 0xffff },
    {   440,   500, 0xffff },
    {   495,   441, 0xffff },
    {   497,   496, 0xffff },
    {   442,   498, 0xffff },
    {   490,   489, 0xffff },
    {   492,   491, 0xffff },
    {   494,   493, 0xffff },
    {   444,   443, 0xffff },
    {   487,   486, 0xffff },
    {   482,   488, 0xffff },
    {   484,   483, 0xffff },
    {   445,   485, 0xffff },
    {   481,   446, 0xffff },
    {   479,   478, 0xffff },
    {   447,   480, 0xffff },
    {   475,   474, 0xffff },
    {   477,   476, 0xffff },
    {   469,   473, 0xffff },
    {   471,   470, 0xffff },
    {   467,   472, 0xffff },
    {   464,   468, 0xffff },
    {   466,   465, 0xffff },
    {   460,   459, 0xffff },
    {   462,   461, 0xffff },
    {   454,   463, 0xffff },
    {   456,   455, 0xffff },
    {   458,   457, 0xffff },
    {   451,   450, 0xffff },
    {   453,   452, 0xffff },
    {   449,   448, 0xffff },
    { 65535, 65535, 0xd50a },
    { 65535, 65535, 0x4612 },
    { 65535, 65535, 0x7418 },
    { 65535, 65535, 0xd58a },
    { 65535, 65535, 0x939a },
    { 65535, 65535, 0x9518 },
    { 65535, 65535, 0x2502 },
    { 65535, 65535, 0xa616 },
    { 65535, 65535, 0x9592 },
    { 65535, 65535, 0xf58a },
    { 65535, 65535, 0x730e },
    { 65535, 65535, 0x1382 },
    { 65535, 65535, 0x7516 },
    { 65535, 65535, 0xb516 },
    { 65535, 65535, 0xb592 },
    { 65535, 65535, 0x8496 },
    { 65535, 65535, 0x450e },
    { 65535, 65535, 0xf504 },
    { 65535, 65535, 0x8518 },
    { 65535, 65535, 0xf484 },
    { 65535, 65535, 0x860e },
    { 65535, 65535, 0x8610 },
    { 65535, 65535, 0xa59c },
    { 65535, 65535, 0x849a },
    { 65535, 65535, 0x458e },
    { 65535, 65535, 0x649a },
    { 65535, 65535, 0xc598 },
    { 65535, 65535, 0x5590 },
    { 65535, 65535, 0xf586 },
    { 65535, 65535, 0xd50c },
    { 65535, 65535, 0xf412 },
    { 65535, 65535, 0xe68c },
    { 65535, 65535, 0x451c },
    { 65535, 65535, 0x4504 },
    { 65535, 65535, 0xb716 },
    { 65535, 65535, 0xd68e },
    { 65535, 65535, 0xf588 },
    { 65535, 65535, 0x850e },
    { 65535, 65535, 0xb59a },
    { 65535, 65535, 0xe588 },
    { 65535, 65535, 0xd510 },
    { 65535, 65535, 0xd694 },
    { 65535, 65535, 0xd692 },
    { 65535, 65535, 0x759c },
    { 65535, 65535, 0xe48c },
    { 65535, 65535, 0x741a },
    { 65535, 65535, 0xd28a },
    { 65535, 65535, 0x6616 },
    { 65535, 65535, 0x630a },
    { 65535, 65535, 0x7496 },
    { 65535, 65535, 0x139c },
    { 65535, 65535, 0xe592 },
    { 65535, 65535, 0x628a },
    { 65535, 65535, 0xa692 },
    { 65535, 65535, 0xc50e },
    { 65535, 65535, 0x658a },
    { 65535, 65535, 0xf506 },
    { 65535, 65535, 0xf390 },
    { 65535, 65535, 0xb61e },
    { 65535, 65535, 0xc612 },
    { 65535, 65535, 0xd60c },
    { 65535, 65535, 0x250e },
    { 65535, 65535, 0x758e },
    { 65535, 65535, 0xe50e },
    { 65535, 65535, 0xc504 },
    { 65535, 65535, 0xc690 },
    { 65535, 65535, 0xe68e },
    { 65535, 65535, 0x650c },
    { 65535, 65535, 0x1294 },
    { 65535, 65535, 0xa69a },
    { 65535, 65535, 0x2402 },
    { 65535, 65535, 0xd490 },
    { 65535, 65535, 0x548a },
    { 65535, 65535, 0xe408 },
    { 65535, 65535, 0x3502 },
    { 65535, 65535, 0xe716 },
    { 65535, 65535, 0x961c },
    { 65535, 65535, 0xa598 },
    { 65535, 65535, 0xd690 },
    { 65535, 65535, 0xd48e },
    { 65535, 65535, 0x951a },
    { 65535, 65535, 0xd48c },
    { 65535, 65535, 0x4396 },
    { 65535, 65535, 0xd50e },
    { 65535, 65535, 0x7416 },
    { 65535, 65535, 0xe486 },
    { 65535, 65535, 0xe690 },
    { 65535, 65535, 0xd592 },
    { 65535, 65535, 0xe50c },
    { 65535, 65535, 0x4486 },
    { 65535, 65535, 0x3504 },
    { 65535, 65535, 0xe48a },
    { 65535, 65535, 0x969a },
    { 65535, 65535, 0xd696 },
    { 65535, 65535, 0x549c },
    { 65535, 65535, 0xf30a },
    { 65535, 65535, 0x2314 },
    { 65535, 65535, 0xf508 },
    { 65535, 65535, 0xb616 },
    { 65535, 65535, 0x451a },
    { 65535, 65535, 0xf60c },
    { 65535, 65535, 0xb614 },
    { 65535, 65535, 0xc492 },
    { 65535, 65535, 0x251a },
    { 65535, 65535, 0x449e },
    { 65535, 65535, 0xe406 },
    { 65535, 65535, 0xc590 },
    { 65535, 65535, 0xe614 },
    { 65535, 65535, 0xc514 },
    { 65535, 65535, 0xe508 },
    { 65535, 65535, 0x141c },
    { 65535, 65535, 0x930a },
    { 65535, 65535, 0x750e },
    { 65535, 65535, 0xe590 },
    { 65535, 65535, 0xd610 },
    { 65535, 65535, 0x3406 },
    { 65535, 65535, 0xd208 },
    { 65535, 65535, 0xf38c },
    { 65535, 65535, 0x859c },
    { 65535, 65535, 0xc510 },
    { 65535, 65535, 0xf516 },
    { 65535, 65535, 0x6516 },
    { 65535, 65535, 0xf494 },
    { 65535, 65535, 0x4488 },
    { 65535, 65535, 0x861c },
    { 65535, 65535, 0xf798 },
    { 65535, 65535, 0x241c },
    { 65535, 65535, 0x959c },
    { 65535, 65535, 0x9612 },
    { 65535, 65535, 0x551c },
    { 65535, 65535, 0xc79c },
    { 65535, 65535, 0x459a },
    { 65535, 65535, 0xf61a },
    { 65535, 65535, 0xb71e },
    { 65535, 65535, 0x659a },
    { 65535, 65535, 0x5588 },
    { 65535, 65535, 0xd60e },
    { 65535, 65535, 0xd590 },
    { 65535, 65535, 0x6308 },
    { 65535, 65535, 0xa614 },
    { 65535, 65535, 0x761c },
    { 65535, 65535, 0x861e },
    { 65535, 65535, 0xa490 },
    { 65535, 65535, 0xe608 },
    { 65535, 65535, 0x5498 },
    { 65535, 65535, 0xf408 },
    { 65535, 65535, 0x9406 },
    { 65535, 65535, 0x5208 },
    { 65535, 65535, 0xb69a },
    { 65535, 65535, 0x2404 },
    { 65535, 65535, 0xe488 },
    { 65535, 65535, 0x4406 },
    { 65535, 65535, 0xf30e },
    { 65535, 65535, 0xb612 },
    { 65535, 65535, 0x751e },
    { 65535, 65535, 0x4590 },
    { 65535, 65535, 0x831a },
    { 65535, 65535, 0xe50a },
    { 65535, 65535, 0x8590 },
    { 65535, 65535, 0xe692 },
    { 65535, 65535, 0x749a },
    { 65535, 65535, 0xd612 },
    { 65535, 65535, 0x6418 },
    { 65535, 65535, 0x9610 },
    { 65535, 65535, 0x751c },
    { 65535, 65535, 0xb61a },
    { 65535, 65535, 0x940e },
    { 65535, 65535, 0x2518 },
    { 65535, 65535, 0x449c },
    { 65535, 65535, 0xc692 },
    { 65535, 65535, 0x1498 },
    { 65535, 65535, 0x940c },
    { 65535, 65535, 0x2382 },
    { 65535, 65535, 0xa698 },
    { 65535, 65535, 0xe60a },
    { 65535, 65535, 0xf58c },
    { 65535, 65535, 0xd58e },
    { 65535, 65535, 0x5488 },
    { 65535, 65535, 0xc718 },
    { 65535, 65535, 0xd594 },
    { 65535, 65535, 0x6594 },
    { 65535, 65535, 0xd596 },
    { 65535, 65535, 0x4510 },
    { 65535, 65535, 0xd614 },
    { 65535, 65535, 0x7614 },
    { 65535, 65535, 0x648a },
    { 65535, 65535, 0xe696 },
    { 65535, 65535, 0x6518 },
    { 65535, 65535, 0x9590 },
    { 65535, 65535, 0x530c },
    { 65535, 65535, 0xc694 },
    { 65535, 65535, 0xb692 },
    { 65535, 65535, 0xd71a },
    { 65535, 65535, 0x650a },
    { 65535, 65535, 0xc696 },
    { 65535, 65535, 0x3404 },
    { 65535, 65535, 0xa610 },
    { 65535, 65535, 0x858c },
    { 65535, 65535, 0x2316 },
    { 65535, 65535, 0xa38a },
    { 65535, 65535, 0xa61a },
    { 65535, 65535, 0x7518 },
    { 65535, 65535, 0x651a },
    { 65535, 65535, 0x2396 },
    { 65535, 65535, 0x1314 },
    { 65535, 65535, 0x858e },
    { 65535, 65535, 0x559a },
    { 65535, 65535, 0x850c },
    { 65535, 65535, 0x351a },
    { 65535, 65535, 0x958e },
    { 65535, 65535, 0xd79e },
    { 65535, 65535, 0xb694 },
    { 65535, 65535, 0x651c },
    { 65535, 65535, 0x7204 },
    { 65535, 65535, 0xa38c },
    { 65535, 65535, 0xa406 },
    { 65535, 65535, 0x859a },
    { 65535, 65535, 0xc716 },
    { 65535, 65535, 0x8204 },
    { 65535, 65535, 0x651e },
    { 65535, 65535, 0xe594 },
    { 65535, 65535, 0xb696 },
    { 65535, 65535, 0x4418 },
    { 65535, 65535, 0x8614 },
    { 65535, 65535, 0xf71e },
    { 65535, 65535, 0x2594 },
    { 65535, 65535, 0x350e },
    { 65535, 65535, 0x6398 },
    { 65535, 65535, 0x971a },
    { 65535, 65535, 0xe514 },
    { 65535, 65535, 0x8386 },
    { 65535, 65535, 0xe504 },
    { 65535, 65535, 0x551e },
    { 65535, 65535, 0xa69c },
    { 65535, 65535, 0xd514 },
    { 65535, 65535, 0xe79c },
    { 65535, 65535, 0xf592 },
    { 65535, 65535, 0xb484 },
    { 65535, 65535, 0xe612 },
    { 65535, 65535, 0xb71a },
    { 65535, 65535, 0x638e },
    { 65535, 65535, 0x4416 },
    { 65535, 65535, 0x859e },
    { 65535, 65535, 0x2480 },
    { 65535, 65535, 0xd512 },
    { 65535, 65535, 0xe694 },
    { 65535, 65535, 0x2614 },
    { 65535, 65535, 0xa404 },
    { 65535, 65535, 0x738c },
    { 65535, 65535, 0xa59a },
    { 65535, 65535, 0xc614 },
    { 65535, 65535, 0x750a },
    { 65535, 65535, 0xb698 },
    { 65535, 65535, 0x3396 },
    { 65535, 65535, 0xb69c },
    { 65535, 65535, 0x750c },
    { 65535, 65535, 0xf20a },
    { 65535, 65535, 0x4616 },
    { 65535, 65535, 0x9494 },
    { 65535, 65535, 0xe582 },
    { 65535, 65535, 0x4206 },
    { 65535, 65535, 0x4614 },
    { 65535, 65535, 0xc69a },
    { 65535, 65535, 0x248e },
    { 65535, 65535, 0xd69c },
    { 65535, 65535, 0xa612 },
    { 65535, 65535, 0x8616 },
    { 65535, 65535, 0x961e },
    { 65535, 65535, 0x4398 },
    { 65535, 65535, 0x7498 },
    { 65535, 65535, 0xd714 },
    { 65535, 65535, 0xc698 },
    { 65535, 65535, 0x9490 },
    { 65535, 65535, 0xc484 },
    { 65535, 65535, 0xd58c },
    { 65535, 65535, 0xb598 },
    { 65535, 65535, 0x7306 },
    { 65535, 65535, 0x838e },
    { 65535, 65535, 0x9410 },
    { 65535, 65535, 0x5616 },
    { 65535, 65535, 0xc61a },
    { 65535, 65535, 0xb71c },
    { 65535, 65535, 0xb404 },
    { 65535, 65535, 0xc71c },
    { 65535, 65535, 0x940a },
    { 65535, 65535, 0xf28c },
    { 65535, 65535, 0x039c },
    { 65535, 65535, 0x9386 },
    { 65535, 65535, 0xf514 },
    { 65535, 65535, 0xe718 },
    { 65535, 65535, 0x7282 },
    { 65535, 65535, 0x9698 },
    { 65535, 65535, 0xb61c },
    { 65535, 65535, 0xa40e },
    { 65535, 65535, 0x9514 },
    { 65535, 65535, 0x8698 },
    { 65535, 65535, 0x8412 },
    { 65535, 65535, 0xf38e },
    { 65535, 65535, 0x851a },
    { 65535, 65535, 0xd504 },
    { 65535, 65535, 0x0498 },
    { 65535, 65535, 0xd71c },
    { 65535, 65535, 0xf30c },
    { 65535, 65535, 0xf410 },
    { 65535, 65535, 0xa61c },
    { 65535, 65535, 0x630e },
    { 65535, 65535, 0x6696 },
    { 65535, 65535, 0x1380 },
    { 65535, 65535, 0x6288 },
    { 65535, 65535, 0xd79c },
    { 65535, 65535, 0x840e },
    { 65535, 65535, 0x528c },
    { 65535, 65535, 0x7410 },
    { 65535, 65535, 0x8308 },
    { 65535, 65535, 0x5592 },
    { 65535, 65535, 0xb618 },
    { 65535, 65535, 0x959a },
    { 65535, 65535, 0xf618 },
    { 65535, 65535, 0xf68a },
    { 65535, 65535, 0xc71a },
    { 65535, 65535, 0xa388 },
    { 65535, 65535, 0x5288 },
    { 65535, 65535, 0xb48e },
    { 65535, 65535, 0x3614 },
    { 65535, 65535, 0xe616 },
    { 65535, 65535, 0xc512 },
    { 65535, 65535, 0xc69c },
    { 65535, 65535, 0x751a },
    { 65535, 65535, 0xc592 },
    { 65535, 65535, 0xa516 },
    { 65535, 65535, 0xe79a },
    { 65535, 65535, 0x5418 },
    { 65535, 65535, 0xb490 },
    { 65535, 65535, 0xf596 },
    { 65535, 65535, 0x2592 },
    { 65535, 65535, 0xb512 },
    { 65535, 65535, 0x8492 },
    { 65535, 65535, 0x7698 },
    { 65535, 65535, 0xe60c },
    { 65535, 65535, 0x7390 },
    { 65535, 65535, 0x9308 },
    { 65535, 65535, 0x6498 },
    { 65535, 65535, 0xa71a },
    { 65535, 65535, 0xa596 },
    { 65535, 65535, 0xf28a },
    { 65535, 65535, 0xe618 },
    { 65535, 65535, 0x8286 },
    { 65535, 65535, 0xf492 },
    { 65535, 65535, 0xa48e },
    { 65535, 65535, 0xf50e },
    { 65535, 65535, 0xf486 },
    { 65535, 65535, 0x9388 },
    { 65535, 65535, 0xf69a },
    { 65535, 65535, 0x8284 },
    { 65535, 65535, 0xe596 },
    { 65535, 65535, 0x0294 },
    { 65535, 65535, 0xc714 },
    { 65535, 65535, 0xe58e },
    { 65535, 65535, 0x6488 },
    { 65535, 65535, 0xd716 },
    { 65535, 65535, 0xb510 },
    { 65535, 65535, 0xe798 },
    { 65535, 65535, 0xd718 },
    { 65535, 65535, 0x6200 },
    { 65535, 65535, 0xe698 },
    { 65535, 65535, 0xf698 },
    { 65535, 65535, 0xf58e },
    { 65535, 65535, 0x7284 },
    { 65535, 65535, 0x4208 },
    { 65535, 65535, 0x938a },
    { 65535, 65535, 0x8306 },
    { 65535, 65535, 0xa40c },
    { 65535, 65535, 0xf614 },
    { 65535, 65535, 0xc594 },
    { 65535, 65535, 0xd616 },
    { 65535, 65535, 0xf582 },
    { 65535, 65535, 0x528a },
    { 65535, 65535, 0xf50c },
    { 65535, 65535, 0xf590 },
    { 65535, 65535, 0x7202 },
    { 65535, 65535, 0x420a },
    { 65535, 65535, 0xd492 },
    { 65535, 65535, 0xe610 },
    { 65535, 65535, 0xf612 },
    { 65535, 65535, 0xf288 },
    { 65535, 65535, 0xf79a },
    { 65535, 65535, 0xe60e },
    { 65535, 65535, 0xa492 },
    { 65535, 65535, 0xd618 },
    { 65535, 65535, 0xf584 },
    { 65535, 65535, 0xe69a },
    { 65535, 65535, 0xf716 },
    { 65535, 65535, 0x738e },
    { 65535, 65535, 0xa512 },
    { 65535, 65535, 0xe71a },
    { 65535, 65535, 0x148c },
    { 65535, 65535, 0xf696 },
    { 65535, 65535, 0xf712 },
    { 65535, 65535, 0x730c },
    { 65535, 65535, 0xf48a },
    { 65535, 65535, 0x759e },
    { 65535, 65535, 0xf106 },
    { 65535, 65535, 0xc596 },
    { 65535, 65535, 0xb594 },
    { 65535, 65535, 0xd698 },
    { 65535, 65535, 0xf694 },
    { 65535, 65535, 0x8410 },
    { 65535, 65535, 0xc616 },
    { 65535, 65535, 0xf68c },
    { 65535, 65535, 0xf60a },
    { 65535, 65535, 0xf71c },
    { 65535, 65535, 0xa69e },
    { 65535, 65535, 0x630c },
    { 65535, 65535, 0xf68e },
    { 65535, 65535, 0xf718 },
    { 65535, 65535, 0x428a },
    { 65535, 65535, 0xf71a },
    { 65535, 65535, 0xf602 },
    { 65535, 65535, 0xf608 },
    { 65535, 65535, 0xf690 },
    { 65535, 65535, 0xb514 },
    { 65535, 65535, 0xf406 },
    { 65535, 65535, 0xf610 },
    { 65535, 65535, 0xf488 },
    { 65535, 65535, 0xf60e },
    { 65535, 65535, 0xf208 },
    { 65535, 65535, 0xe79e },
    { 65535, 65535, 0x1592 },
    { 65535, 65535, 0xc69e },
    { 65535, 65535, 0xe58c },
    { 65535, 65535, 0xe58a },
    { 65535, 65535, 0xf404 },
    { 65535, 65535, 0xd71e },
    { 65535, 65535, 0xe71e },
    { 65535, 65535, 0xc71e },
    { 65535, 65535, 0xf714 },
    { 65535, 65535, 0xb69e },
    { 65535, 65535, 0xf79c },
    { 65535, 65535, 0xf692 },
    { 65535, 65535, 0xe71c },
    { 65535, 65535, 0xf50a },
    { 65535, 65535, 0xb596 },
    { 65535, 65535, 0xc712 },
    { 65535, 65535, 0xa514 },
    { 65535, 65535, 0xd69a },
    { 65535, 65535, 0xc618 },
    { 65535, 65535, 0x9492 },
    { 65535, 65535, 0xa61e },
    { 65535, 65535, 0xffde },
};

/**********************
 *      MACROS
 **********************/
#ifndef ARRAYSIZE
#define ARRAYSIZE(a) sizeof(a)/sizeof(a[0])
#endif

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
void lv_hms_init(void)
{
    lv_img_decoder_t * dec = lv_img_decoder_create();
    lv_img_decoder_set_info_cb(dec, decoder_info);
    lv_img_decoder_set_open_cb(dec, decoder_open);
    lv_img_decoder_set_close_cb(dec, decoder_close);
    lv_img_decoder_set_read_line_cb(dec, decoder_read_line);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
/**
 * Get info about an SJPG / JPG image
 * @param decoder pointer to the decoder where this function belongs
 * @param src can be file name or pointer to a C array
 * @param header store the info here
 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
 */
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
{
    LV_UNUSED(decoder);

    /*Check whether the type `src` is known by the decoder*/
    /* Read the SJPG/JPG header and find `width` and `height` */

    lv_img_src_t src_type = lv_img_src_get_type(src);          /*Get the source type*/

    lv_res_t ret = LV_RES_OK;

    if(src_type == LV_IMG_SRC_VARIABLE) {
        const lv_img_dsc_t * img_dsc = src;
        uint8_t * raw_hms_data = (uint8_t *)img_dsc->data;
        const uint32_t raw_hms_data_size = img_dsc->data_size;

        if(!strncmp((char *)raw_hms_data, "HMS_", strlen("HMS_"))) {

            raw_hms_data += 14; //seek to res info ... refer hms format
            header->always_zero = 0;
            header->cf = LV_IMG_CF_RAW;

            header->w = *raw_hms_data++;
            header->w |= *raw_hms_data++ << 8;

            header->h = *raw_hms_data++;
            header->h |= *raw_hms_data++ << 8;

            return ret;

        }
    }
    else if(src_type == LV_IMG_SRC_FILE) {
        const char * fn = src;
        if(strcmp(lv_fs_get_ext(fn), "hms") == 0) {

            uint8_t buff[8];
            memset(buff, 0, sizeof(buff));

            lv_fs_file_t file;
            lv_fs_res_t res = lv_fs_open(&file, fn, LV_FS_MODE_RD);
            if(res != LV_FS_RES_OK) return 78;

            uint32_t rn;
            res = lv_fs_read(&file, buff, 8, &rn);
            if(res != LV_FS_RES_OK || rn != 8) {
                lv_fs_close(&file);
                return LV_RES_INV;
            }

            if(strncmp((char *)buff, "HMS_", 4) == 0) {
                lv_fs_seek(&file, HMS_X_RES_OFFSET, LV_FS_SEEK_SET);
                res = lv_fs_read(&file, buff, 4, &rn);
                if(res != LV_FS_RES_OK || rn != 4) {
                    lv_fs_close(&file);
                    return LV_RES_INV;
                }
                header->always_zero = 0;
                header->cf = LV_IMG_CF_RGB565;
                uint8_t * raw_hms_data = buff;
                header->w  = *raw_hms_data++;
                header->w |= *raw_hms_data++ << 8;
                header->h  = *raw_hms_data++;
                header->h |= *raw_hms_data++ << 8;
                lv_fs_close(&file);
                return LV_RES_OK;

            }
        }
    }

    return LV_RES_INV;
}

static int img_data_cb(HMS* hms, void * data, JRECT * rect)
{
    io_source_t* io = &hms->io;
    uint8_t * cache = io->img_cache_buff;
    const int xres = io->img_cache_x_res;
    uint8_t * buf = data;
    const int INPUT_PIXEL_SIZE = 3;
    const int row_width = rect->right - rect->left + 1; // Row width in pixels.
    const int row_size = row_width * INPUT_PIXEL_SIZE;  // Row size (bytes).

    for(int y = rect->top; y <= rect->bottom; y++) {
        int row_offset = y * xres * INPUT_PIXEL_SIZE + rect->left * INPUT_PIXEL_SIZE;
        memcpy(cache + row_offset, buf, row_size);
        buf += row_size;
    }

    return 1;
}

static size_t input_func(HMS *hms, uint8_t * buff, size_t ndata)
{
    io_source_t* io = &hms->io;

    if(!io) return 0;

    if(io->type == HMS_IO_SOURCE_C_ARRAY) {
        const uint32_t bytes_left = io->raw_hms_data_size - io->raw_hms_data_next_read_pos;
        const uint32_t to_read = ndata <= bytes_left ? (uint32_t)ndata : bytes_left;
        if(to_read == 0)
            return 0;
        if(buff) {
            memcpy(buff, io->raw_hms_data + io->raw_hms_data_next_read_pos, to_read);
        }
        io->raw_hms_data_next_read_pos += to_read;
        return to_read;
    }
    else if(io->type == HMS_IO_SOURCE_DISK) {

        lv_fs_file_t * lv_file_p = &(io->lv_file);

        if(buff) {
            uint32_t rn = 0;
            lv_fs_read(lv_file_p, buff, (uint32_t)ndata, &rn);
            return rn;
        }
        else {
            uint32_t pos;
            lv_fs_tell(lv_file_p, &pos);
            lv_fs_seek(lv_file_p, (uint32_t)(ndata + pos), LV_FS_SEEK_SET);
            return ndata;
        }
    }
    return 0;
}

/**
 * Open SJPG image and return the decided image
 * @param decoder pointer to the decoder where this function belongs
 * @param dsc pointer to a descriptor which describes this decoding session
 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
 */
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
    LV_UNUSED(decoder);
    lv_res_t lv_ret = LV_RES_OK;

    if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
        uint8_t * data;
        HMS * hms = (HMS *) dsc->user_data;
        const uint32_t raw_hms_data_size = ((lv_img_dsc_t *)dsc->src)->data_size;
        if(hms == NULL) {
            hms =  lv_mem_alloc(sizeof(HMS));
            if(!hms) return LV_RES_INV;

            memset(hms, 0, sizeof(HMS));

            dsc->user_data = hms;
            hms->hms_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
            hms->hms_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
        }

        if(!strncmp((char *) hms->hms_data, "HMS_", strlen("HMS_"))) {

            data = hms->hms_data;
            data += 14;

            hms->hms_x_res = *data++;
            hms->hms_x_res |= *data++ << 8;

            hms->hms_y_res = *data++;
            hms->hms_y_res |= *data++ << 8;

            hms->hms_total_frames = *data++;
            hms->hms_total_frames |= *data++ << 8;

            hms->hms_frame_height = *data++;
            hms->hms_frame_height |= *data++ << 8;

            hms->frame_base_array = lv_mem_alloc(sizeof(uint8_t *) * hms->hms_total_frames);
            if(! hms->frame_base_array) {
                lv_hms_cleanup(hms);
                hms = NULL;
                return LV_RES_INV;
            }

            hms->frame_base_offset = NULL;

            uint8_t * img_frame_base = data +  hms->hms_total_frames * 2;
            hms->frame_base_array[0] = img_frame_base;

            for(int i = 1; i <  hms->hms_total_frames; i++) {
                int offset = *data++;
                offset |= *data++ << 8;
                hms->frame_base_array[i] = hms->frame_base_array[i - 1] + offset;
            }
            hms->hms_cache_frame_index = -1;
            hms->frame_cache = (void *)lv_mem_alloc(hms->hms_x_res * hms->hms_frame_height * 3/*2*/);
            if(! hms->frame_cache) {
                lv_hms_cleanup(hms);
                hms = NULL;
                return LV_RES_INV;
            }
            hms->io.img_cache_buff = hms->frame_cache;
            hms->io.img_cache_x_res = hms->hms_x_res;

            hms->io.type = HMS_IO_SOURCE_C_ARRAY;
            hms->io.lv_file.file_d = NULL;
            dsc->img_data = NULL;
            return lv_ret;
        }
    }
    else if(dsc->src_type == LV_IMG_SRC_FILE) {
        /* If all fine, then the file will be kept open */
        const char * fn = dsc->src;
        uint8_t * data;

        if(strcmp(lv_fs_get_ext(fn), "hms") == 0) {

            uint8_t buff[16];
            memset(buff, 0, sizeof(buff));


            lv_fs_file_t lv_file;
            lv_fs_res_t res = lv_fs_open(&lv_file, fn, LV_FS_MODE_RD);
            if(res != LV_FS_RES_OK) {
                return 78;
            }


            uint32_t rn;
            res = lv_fs_read(&lv_file, buff, HMS_FRAME_INFO_ARRAY_OFFSET, &rn);
            if(res != LV_FS_RES_OK || rn != HMS_FRAME_INFO_ARRAY_OFFSET) {
                lv_fs_close(&lv_file);
                return LV_RES_INV;
            }

            if(strncmp((char *)buff, "HMS_", 4) == 0) {

                HMS* hms = (HMS*)dsc->user_data;
                if(hms == NULL) {
                    hms = lv_mem_alloc(sizeof(HMS));
                    if(! hms) {
                        lv_fs_close(&lv_file);
                        return LV_RES_INV;
                    }
                    memset(hms, 0, sizeof(HMS));

                    dsc->user_data = hms;
                    hms->hms_data = (uint8_t *)((lv_img_dsc_t *)(dsc->src))->data;
                    hms->hms_data_size = ((lv_img_dsc_t *)(dsc->src))->data_size;
                }
                data = buff;
                data += 8;

                hms->hms_x_res  = *data++;
                hms->hms_x_res |= *data++ << 8;

                hms->hms_y_res  = *data++;
                hms->hms_y_res |= *data++ << 8;

                hms->hms_frame_height  = *data++;
                hms->hms_frame_height |= *data++ << 8;

                hms->hms_total_frames  = *data++;
                hms->hms_total_frames |= *data++ << 8;

                hms->frame_base_array = NULL;//lv_mem_alloc( sizeof(uint8_t *) * hms->hms_total_frames );
                hms->frame_base_offset = lv_mem_alloc(sizeof(int) * hms->hms_total_frames);
                if(! hms->frame_base_offset) {
                    lv_fs_close(&lv_file);
                    lv_hms_cleanup(hms);
                    return LV_RES_INV;
                }

                hms->frame_size = lv_mem_alloc(sizeof(uint16_t) * hms->hms_total_frames);
                if (!hms->frame_size)
                {
                    lv_fs_close(&lv_file);
                    lv_hms_cleanup(hms);
                    return LV_RES_INV;
                }
                int img_frame_start_offset = (HMS_FRAME_INFO_ARRAY_OFFSET + hms->hms_total_frames * 2);
                hms->frame_base_offset[0] = img_frame_start_offset; //pointer used to save integer for now...

                for(int i = 0; i <  hms->hms_total_frames; i++) {
                    res = lv_fs_read(&lv_file, buff, 2, &rn);
                    if(res != LV_FS_RES_OK || rn != 2) {
                        lv_fs_close(&lv_file);
                        return LV_RES_INV;
                    }

                    data = buff;
                    hms->frame_size[i]  = *data++;
                    hms->frame_size[i] |= *data++ << 8;
                    if (i > 0)
                        hms->frame_base_offset[i] = hms->frame_base_offset[i - 1] + hms->frame_size[i - 1];
                }

                hms->hms_cache_frame_index = -1; //INVALID AT BEGINNING for a forced compare mismatch at first time.
                hms->frame_cache = (void *)lv_mem_alloc(hms->hms_x_res * hms->hms_frame_height * 2);
                if(! hms->frame_cache) {
                    lv_fs_close(&lv_file);
                    lv_hms_cleanup(hms);
                    return LV_RES_INV;
                }
                hms->io.img_cache_buff = hms->frame_cache;
                hms->io.img_cache_x_res = hms->hms_x_res;

                hms->io.type = HMS_IO_SOURCE_DISK;
                hms->io.lv_file = lv_file;
                dsc->img_data = NULL;
                return LV_RES_OK;
            }
        }
    }

    return LV_RES_INV;
}

/**
 * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
 * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL)
 * @param decoder pointer to the decoder the function associated with
 * @param dsc pointer to decoder descriptor
 * @param x start x coordinate
 * @param y start y coordinate
 * @param len number of pixels to decode
 * @param buf a buffer to store the decoded pixels
 * @return LV_RES_OK: ok; LV_RES_INV: failed
 */

static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
                                  lv_coord_t len, uint8_t * buf)
{
    LV_UNUSED(decoder);
    if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
        HMS * hms = (HMS *) dsc->user_data;

        int hms_req_frame_index = y / hms->hms_frame_height;

        /*If line not from cache, refresh cache */
        if(hms_req_frame_index != hms->hms_cache_frame_index) {
            hms->io.raw_hms_data = hms->frame_base_array[ hms_req_frame_index ];
            if(hms_req_frame_index == (hms->hms_total_frames - 1)) {
                /*This is the last frame. */
                const uint32_t frame_offset = (uint32_t)(hms->io.raw_hms_data - hms->hms_data);
                hms->io.raw_hms_data_size = hms->hms_data_size - frame_offset;
            }
            else {
                hms->io.raw_hms_data_size =
                    (uint32_t)(hms->frame_base_array[hms_req_frame_index + 1] - hms->io.raw_hms_data);
            }
            hms->io.raw_hms_data_next_read_pos = 0;
            //rc = jd_prepare(hms->tjpeg_jd, input_func, hms->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(hms->io));
            //if(rc != JDR_OK) return LV_RES_INV;
            //rc = jd_decomp(hms->tjpeg_jd, img_data_cb, 0);
            //if(rc != JDR_OK) return LV_RES_INV;
            hms->hms_cache_frame_index = hms_req_frame_index;
        }

        int offset = 0;
        uint8_t * cache = (uint8_t *)hms->frame_cache + x * 3 + (y % hms->hms_frame_height) * hms->hms_x_res *
                          3;

#if  LV_COLOR_DEPTH == 32
        for(int i = 0; i < len; i++) {
            buf[offset + 3] = 0xff;
            buf[offset + 2] = *cache++;
            buf[offset + 1] = *cache++;
            buf[offset + 0] = *cache++;
            offset += 4;
        }

#elif  LV_COLOR_DEPTH == 16

        for(int i = 0; i < len; i++) {
            uint16_t col_16bit = (*cache++ & 0xf8) << 8;
            col_16bit |= (*cache++ & 0xFC) << 3;
            col_16bit |= (*cache++ >> 3);
#if  LV_BIG_ENDIAN_SYSTEM == 1 || LV_COLOR_16_SWAP == 1
            buf[offset++] = col_16bit >> 8;
            buf[offset++] = col_16bit & 0xff;
#else
            buf[offset++] = col_16bit & 0xff;
            buf[offset++] = col_16bit >> 8;
#endif // LV_BIG_ENDIAN_SYSTEM
        }

#elif  LV_COLOR_DEPTH == 8

        for(int i = 0; i < len; i++) {
            uint8_t col_8bit = (*cache++ & 0xC0);
            col_8bit |= (*cache++ & 0xe0) >> 2;
            col_8bit |= (*cache++ & 0xe0) >> 5;
            buf[offset++] = col_8bit;
        }
#else
#error Unsupported LV_COLOR_DEPTH


#endif // LV_COLOR_DEPTH
        return LV_RES_OK;
    }
    else if(dsc->src_type == LV_IMG_SRC_FILE) {
        HMS * hms = (HMS *) dsc->user_data;
        lv_res_t rc;
        int hms_req_frame_index = y / hms->hms_frame_height;

        lv_fs_file_t * lv_file_p = &(hms->io.lv_file);
        if(!lv_file_p) goto end;

        /*If line not from cache, refresh cache */
        if(hms_req_frame_index != hms->hms_cache_frame_index) {
            hms->io.raw_hms_data_next_read_pos = (int)(hms->frame_base_offset[hms_req_frame_index]);
            lv_fs_seek(&(hms->io.lv_file), hms->io.raw_hms_data_next_read_pos, LV_FS_SEEK_SET);

            hms->worksize = hms->frame_size[hms_req_frame_index];
            hms->workb = (uint32_t*)lv_mem_alloc(hms->worksize);
            if (!hms->workb) {
                lv_hms_cleanup(hms);
                hms = NULL;
                return LV_RES_INV;
            }
            //rc = jd_prepare(hms->tjpeg_jd, input_func, hms->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(hms->io));
            rc = hms_prepare(hms);
            if(rc != LV_RES_OK) return LV_RES_INV;

            //rc = jd_decomp(hms->tjpeg_jd, img_data_cb, 0);
            rc = hms_decode(hms);
            if(rc != LV_RES_OK) return LV_RES_INV;

            if (hms->workb)
            {
                lv_mem_free(hms->workb);
                hms->workb = NULL;
            }

            hms->hms_cache_frame_index = hms_req_frame_index;
        }

        int offset = 0;
        uint16_t* cache = (uint16_t*)(hms->frame_cache + x * 2 + (y % hms->hms_frame_height) * hms->hms_x_res * 2);

#if LV_COLOR_DEPTH == 32
        for(int i = 0; i < len; i++) {
            buf[offset + 3] = 0xff;
            buf[offset + 2] = ((*cache) >> 8) & 0xF8;
            buf[offset + 1] = ((*cache) >> 2) & 0xFC;
            buf[offset + 0] = ((*cache) << 3) & 0xF8;
            cache++;
            offset += 4;
        }
#elif  LV_COLOR_DEPTH == 16

        for(int i = 0; i < len; i++) {
#if  LV_BIG_ENDIAN_SYSTEM == 1 || LV_COLOR_16_SWAP == 1
            buf[offset++] = (*cache) >> 8;
            buf[offset++] = (*cache) & 0xff;
#else
            buf[offset++] = (*cache) & 0xff;
            buf[offset++] = (*cache) >> 8;
#endif // LV_BIG_ENDIAN_SYSTEM
            cache++;
        }

#elif  LV_COLOR_DEPTH == 8

        for(int i = 0; i < len; i++) {
            uint8_t col_8bit = (*cache++ & 0xC0);
            col_8bit |= (*cache++ & 0xe0) >> 2;
            col_8bit |= (*cache++ & 0xe0) >> 5;
            buf[offset++] = col_8bit;
        }

#else
#error Unsupported LV_COLOR_DEPTH


#endif // LV_COLOR_DEPTH

        return LV_RES_OK;
    }
end:
    return LV_RES_INV;
}

/**
 * Free the allocated resources
 * @param decoder pointer to the decoder where this function belongs
 * @param dsc pointer to a descriptor which describes this decoding session
 */
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
    LV_UNUSED(decoder);
    /*Free all allocated data*/
    HMS * hms = (HMS *) dsc->user_data;
    if(!hms) return;

    switch(dsc->src_type) {
        case LV_IMG_SRC_FILE:
            if(hms->io.lv_file.file_d) {
                lv_fs_close(&(hms->io.lv_file));
            }
            lv_hms_cleanup(hms);
            break;

        case LV_IMG_SRC_VARIABLE:
            lv_hms_cleanup(hms);
            break;

        default:
            ;
    }
}

static lv_res_t hms_prepare(HMS* hms)
{
    //
    io_source_t*  io = &hms->io;
    lv_fs_file_t* lv_file_p = &(io->lv_file);
    uint32_t rn = 0;

    lv_fs_read(lv_file_p, hms->workb, (uint32_t)hms->worksize, &rn);
    if (rn != hms->worksize)
    {
        LV_LOG_WARN("read len:%d < %d!\r\n", rn, hms->worksize);
    }

    return LV_RES_OK;
}

static lv_res_t hms_decode(HMS* hms)
{
    uint16_t* cache = (uint16_t*)hms->io.img_cache_buff;
    uint32_t  ofs   = 0;
    uint16_t  cc    = 0;
    uint32_t  framesize = hms->hms_frame_height * hms->hms_x_res;

    hms->enc_word = hms->workb[ofs++];
    hms->enc_bits = 32;

    while (framesize)
    {
        if (hms->enc_word & 0x80000000)
            cc = huffTree[cc].right;
        else
            cc = huffTree[cc].left;

        hms->enc_word <<= 1;
        hms->enc_bits--;
        
        if (huffTree[cc].left == 0xFFFF)
        {
            *cache++ = huffTree[cc].color;
            framesize--;
            cc = 0;
        }

        if (hms->enc_bits == 0)
        {
            hms->enc_word = hms->workb[ofs++];
            hms->enc_bits = 32;
        }
    }

    return LV_RES_OK;
}

static void lv_hms_free(HMS * hms)
{
    if(hms->frame_cache) lv_mem_free(hms->frame_cache);
    if(hms->frame_base_array) lv_mem_free(hms->frame_base_array);
    if(hms->frame_base_offset) lv_mem_free(hms->frame_base_offset);
    if(hms->frame_size) lv_mem_free(hms->frame_size);
    if(hms->workb) lv_mem_free(hms->workb);
}

static void lv_hms_cleanup(HMS * hms)
{
    if(! hms) return;

    lv_hms_free(hms);
    lv_mem_free(hms);
}

#endif /*LV_USE_SJPG*/
